using System;

namespace OpenRay
{
	//Immutable Class
	public class PointPhongLight : PhongLight
	{
		private readonly Point location;
		
		private readonly Vector spotDirection;
		private readonly float cosineSpotCutoff, spotExponent;
		private readonly float constantAttenuation, linearAttenuation, quadraticAttenuation;
		
		public PointPhongLight ( Color A, Color D, Color S, Point L, IScene s )
			: base( A, D, S, s )
		{
			location = L;
			
			spotDirection = new Vector( 0f, 0f, -1f );
			spotExponent = 0;
			cosineSpotCutoff = (float)Math.Cos( 180 * Math.PI / 180 );
			
			constantAttenuation = 1;
			linearAttenuation = 0;
			quadraticAttenuation = 0;
		}
		
		public override Color ComputeLighting( Color materialAmbient, Color materialDiffuse, Color materialSpecular, float materialShininess,
                                 	   		   Point worldHit, Vector normalizedViewer, Vector surfaceNormal ) 
		{
			Color ambientTerm = BlinnPhongAmbient( materialAmbient );
			
			Vector toLight = location - worldHit;
			
			if ( isShadowed(worldHit, toLight) )
				return ambientTerm;
			
			Vector normalizedToLight = Vector.Normalize( toLight );
			
			float spotEffect = 1f;
			
			if ( cosineSpotCutoff != -1f ) {
				float dot = Vector.DotProduct( normalizedToLight, spotDirection );
				spotEffect = ( dot < cosineSpotCutoff ) ? 0f : (float)Math.Pow( Math.Max( 0, dot ), spotExponent );
			}
			
			float attenuation = 1f;
			
			if ( constantAttenuation != 1.0f || linearAttenuation != 0.0f || quadraticAttenuation != 0.0f ) {
				float distanceSquared = Vector.DotProduct( toLight, toLight );
				float distance = (float)Math.Sqrt( distanceSquared );
				attenuation = 1f / ( constantAttenuation + distance * linearAttenuation + distanceSquared * quadraticAttenuation );
			}
			
			
			Color nonAmbientTerm = BlinnPhongNonAmbient( materialDiffuse, materialSpecular, materialShininess,
			                     			         normalizedToLight, normalizedViewer, surfaceNormal );
			
			return ambientTerm + nonAmbientTerm * spotEffect * attenuation;
		}
	}
}

